﻿using System;
using GeoAPI.Geometries;

namespace YJKGridTopologyCal.Geometries.Implementation
{
	public class PackedCoordinateSequenceFactory : ICoordinateSequenceFactory
	{
		public PackedCoordinateSequenceFactory() : this(PackedCoordinateSequenceFactory.PackedType.Double)
		{
		}

		public PackedCoordinateSequenceFactory(PackedCoordinateSequenceFactory.PackedType type) : this(type, 3)
		{
		}

		public PackedCoordinateSequenceFactory(PackedCoordinateSequenceFactory.PackedType type, int dimension)
		{
			this.Type = type;
			this.Dimension = dimension;
		}

		public PackedCoordinateSequenceFactory.PackedType Type
		{
			get
			{
				return this.type;
			}
			set
			{
				if (value != PackedCoordinateSequenceFactory.PackedType.Double && value != PackedCoordinateSequenceFactory.PackedType.Float)
				{
					throw new ArgumentException("Unknown type " + value);
				}
				this.type = value;
			}
		}

		public int Dimension
		{
			get
			{
				return this.dimension;
			}
			set
			{
				this.dimension = value;
			}
		}

		public ICoordinateSequence Create(Coordinate[] coordinates)
		{
			if (this.type == PackedCoordinateSequenceFactory.PackedType.Double)
			{
				return new PackedDoubleCoordinateSequence(coordinates, this.dimension);
			}
			return new PackedFloatCoordinateSequence(coordinates, this.dimension);
		}

		public ICoordinateSequence Create(ICoordinateSequence coordSeq)
		{
			if (this.type == PackedCoordinateSequenceFactory.PackedType.Double)
			{
				return new PackedDoubleCoordinateSequence(coordSeq.ToCoordinateArray(), this.dimension);
			}
			return new PackedFloatCoordinateSequence(coordSeq.ToCoordinateArray(), this.dimension);
		}

		public ICoordinateSequence Create(int size, Ordinates ordinates)
		{
			return this.Create(size, OrdinatesUtility.OrdinatesToDimension(ordinates));
		}

		public Ordinates Ordinates
		{
			get
			{
				return Ordinates.XYZ;
			}
		}

		public ICoordinateSequence Create(double[] packedCoordinates, int dimension)
		{
			if (this.type == PackedCoordinateSequenceFactory.PackedType.Double)
			{
				return new PackedDoubleCoordinateSequence(packedCoordinates, dimension);
			}
			return new PackedFloatCoordinateSequence(packedCoordinates, dimension);
		}

		public ICoordinateSequence Create(float[] packedCoordinates, int dimension)
		{
			if (this.type == PackedCoordinateSequenceFactory.PackedType.Double)
			{
				return new PackedDoubleCoordinateSequence(packedCoordinates, dimension);
			}
			return new PackedFloatCoordinateSequence(packedCoordinates, dimension);
		}

		public ICoordinateSequence Create(int size, int dimension)
		{
			if (this.type == PackedCoordinateSequenceFactory.PackedType.Double)
			{
				return new PackedDoubleCoordinateSequence(size, dimension);
			}
			return new PackedFloatCoordinateSequence(size, dimension);
		}

		public static readonly PackedCoordinateSequenceFactory DoubleFactory = new PackedCoordinateSequenceFactory(PackedCoordinateSequenceFactory.PackedType.Double);

		public static readonly PackedCoordinateSequenceFactory FloatFactory = new PackedCoordinateSequenceFactory(PackedCoordinateSequenceFactory.PackedType.Float);

		private PackedCoordinateSequenceFactory.PackedType type;

		private int dimension = 3;

		public enum PackedType
		{
			Double,
			Float
		}
	}
}
